package com.zmn.oms.business.impl.log;

import com.google.common.collect.Lists;
import com.zmn.common.constant.GlobalConsts;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.common.utils.date.DateUtil;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.oms.business.interfaces.log.OrderLogBService;
import com.zmn.oms.common.constant.OrderLogConsts;
import com.zmn.oms.common.constant.OrderStatusConsts;
import com.zmn.oms.manager.utils.MongodbConsts;
import com.zmn.oms.model.dto.log.OperatorAchievementsDto;
import com.zmn.oms.model.dto.log.OrderLogQuery;
import com.zmn.oms.model.entity.log.OrderLog;
import com.zmn.oms.model.entity.work.OrderWork;
import com.zmn.oms.services.interfaces.work.OrderWorkService;
import com.zmn.track.dubbo.dro.apply.cancel.OrderCancelApplyLogDRO;
import com.zmn.track.dubbo.dto.TrackWorkLogDRO;
import com.zmn.track.dubbo.interfaces.apply.cancel.OrderCancelApplyListRemoteService;
import com.zmn.track.dubbo.interfaces.trackwork.TrackWorkListRemoteService;
import io.shardingsphere.core.keygen.DefaultKeyGenerator;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.mapreduce.GroupBy;
import org.springframework.data.mongodb.core.mapreduce.GroupByResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;

/**
 * 类描述：工单log
 *
 * @author lujia
 * @date 2018/12/27 20:18
 */
@Service
public class OrderLogBServiceImpl implements OrderLogBService {

    @Autowired
    MongoTemplate mongoTemplate;
    @Autowired
    DefaultKeyGenerator defaultKeyGenerator;
    @Resource
    OrderWorkService orderWorkService;

    @Reference(version = com.zmn.track.dubbo.consts.DubboConsts.INTERFACE_VERSION, check = false)
    private TrackWorkListRemoteService trackWorkListRemoteService;
    @Reference(version = com.zmn.track.dubbo.consts.DubboConsts.INTERFACE_VERSION, check = false)
    private OrderCancelApplyListRemoteService orderCancelApplyListRemoteService;

    @Override
    public List<OrderLog> findOrderLogsByTypes(Long workId, List<Integer> types) {
        Query query = new Query();
        Criteria criteria = new Criteria();
        criteria.and("workId").is(workId);
        criteria.and("type").in(types);
        query.addCriteria(criteria);
        query.with(Sort.by(Sort.Order.desc("createTime")));
        return mongoTemplate.find(query, OrderLog.class);
    }

    @Override
    public List<OrderLog> findOrderLogsAscByTypes(Long orderId, List<Integer> types) {
        Query query = new Query();
        Criteria criteria = new Criteria();
        criteria.and("orderId").is(orderId);
        criteria.and("type").in(types);
        query.addCriteria(criteria);
        query.with(Sort.by(Sort.Order.asc("createTime")));
        return mongoTemplate.find(query, OrderLog.class);
    }

    @Override
    public List<OrderLog> findOrderLogsByOperator(Long orderId, Long operatorId) {
        Query query = new Query();
        Criteria criteria = new Criteria();
        criteria.and("orderId").is(orderId);
        criteria.and("operatorId").is(operatorId);
        query.addCriteria(criteria);
        query.with(Sort.by(Sort.Order.desc("createTime")));
        return mongoTemplate.find(query, OrderLog.class);
    }

    @Override
    public List<OrderLog> findOrderLogsByMaster(Long orderId, Long masterId) {
        Query query = new Query();
        Criteria criteria1 = new Criteria();
        criteria1.and("orderId").is(orderId);
        criteria1.and("operatorId").is(masterId);
        Criteria criteria2 = new Criteria();
        criteria2.and("orderId").is(orderId);
        criteria2.and("type").is(OrderLogConsts.ORDER_LOG_TYPE_PLAT_MASTER_REMARK);
        query.addCriteria(new Criteria().orOperator(criteria1, criteria2));
        query.with(Sort.by(Sort.Order.desc("createTime")));
        return mongoTemplate.find(query, OrderLog.class);
    }

    @Override
    public List<OrderLog> findOrderLogsByOrderId(Long orderId) {
        Query query = new Query();
        Criteria criteria = new Criteria();
        criteria.and("orderId").is(orderId);
        query.addCriteria(criteria);
        query.with(Sort.by(Sort.Order.desc("createTime")));
        return mongoTemplate.find(query, OrderLog.class);
    }

    @Override
    public List<OrderLog> findOrderLogsByWorkId(Long workId) {
        Query query = new Query();
        Criteria criteria = new Criteria();
        criteria.and("workId").is(workId);
        query.addCriteria(criteria);
        query.with(Sort.by(Sort.Order.desc("createTime")));
        return mongoTemplate.find(query, OrderLog.class);
    }

    @Override
    public List<OrderLog> findOrderLogsByQuery(OrderLogQuery orderLogQuery) {
        Query query = new Query();
        Criteria criteria = new Criteria();
        criteria.and("workId").is(orderLogQuery.getOrderId());
        if (NumberUtil.isNotNullOrZero(orderLogQuery.getOperatorId())) {
            criteria.and("operatorId").is((long) orderLogQuery.getOperatorId());
        }
        query.addCriteria(criteria);
        query.with(Sort.by(Sort.Order.desc("createTime")));
        return mongoTemplate.find(query, OrderLog.class);
    }

    @Override
    public OrderLog findOrderLogById(Long id) {
        return mongoTemplate.findById(id, OrderLog.class);
    }

    @Override
    public void save(OrderLog orderLog) {

        if (orderLog.getOrderId() != null && orderLog.getWorkId() != null) {
            OrderWork orderWork = orderWorkService.findOrderWorkByKey(orderLog.getOrderId(), orderLog.getWorkId());
            if (!Objects.isNull(orderWork)) {
                orderLog.setMasterId(Optional.ofNullable(orderWork.getMasterId()).orElse(0));
                orderLog.setManageCompanyId(Optional.ofNullable(orderWork.getManageCompanyId()).orElse(0));
                orderLog.setPlat(Optional.ofNullable(orderWork.getPlat()).orElse(0));
                orderLog.setPlatWork(Optional.ofNullable(orderWork.getPlatWork()).orElse(0));
            }
        }

        if (orderLog.getCreateTime() == null) {
            orderLog.setCreateTime(new Date());
        }

        if (StringUtils.isBlank(orderLog.getOperatorTypeName()) && orderLog.getOperatorType() != null) {
            orderLog.setOperatorTypeName(GlobalConsts.getOperatorTypeName(orderLog.getOperatorType()));
        }

        mongoTemplate.save(orderLog);
    }

    @Override
    public List<OperatorAchievementsDto> findOperatorAchievements(Date startTime, Date endTime,
                                                                  Integer orderLogType, boolean currentOperatorOnly) {

        // 设置查询条件
        List<Criteria> criteriaList = new LinkedList<>();
        criteriaList.add(Criteria.where("type").is(orderLogType));
        criteriaList.add(Criteria.where("createTime").gte(startTime).lt(endTime));

        // 封装查询对象
        Criteria condition = null;
        Criteria[] criteriaArr = new Criteria[criteriaList.size()];
        for (int i = 0, len = criteriaList.size(); i < len; i++) {
            criteriaArr[i] = criteriaList.get(i);
        }
        condition = new Criteria().andOperator(criteriaArr);

        // 设置分组条件
        GroupBy groupBy = GroupBy.key("operatorId")
                .initialDocument("{achievements:0, operatorId:0, operator:'', type:0, "
                        + "typeName:'', operatorType:0, operatorTypeName: ''}")
                .reduceFunction("function(doc, prev) {"
                        + "prev.operatorId = doc.operatorId;"
                        + "prev.operator = doc.operator;"
                        + "prev.type = doc.type;"
                        + "prev.typeName = doc.typeName;"
                        + "prev.achievements++;"
                        + "}");

        // 执行查询
        GroupByResults<OperatorAchievementsDto> groupByResults = mongoTemplate.group(
                condition, MongodbConsts.ORDER_LOG_TABLE, groupBy, OperatorAchievementsDto.class);

        // 封装返回结果
        List<OperatorAchievementsDto> results = new LinkedList<>();
        Iterator<OperatorAchievementsDto> iterator = groupByResults.iterator();
        while (iterator.hasNext()) {
            results.add(iterator.next());
        }

        return results;
    }

    public List<OrderLog> findNewTrackLogsByWorkId(Long workId) {
        if (NumberUtil.isNullOrZero(workId)) {
            return Lists.newArrayList();
        }
        ResponseDTO<List<TrackWorkLogDRO>> listResponseDTO = null;
        try {
            listResponseDTO = trackWorkListRemoteService.listTrackWorkLogByWorkId(workId);
        } catch (Exception e) {
            e.printStackTrace();
            return Collections.EMPTY_LIST;
        }

        List<OrderLog> orderLogs = new ArrayList<>();

        if (!listResponseDTO.isSuccess()) {
            return orderLogs;
        }

        listResponseDTO.getData().forEach(trackLog -> {
            OrderLog orderLog = new OrderLog();
            orderLog.setType(OrderLogConsts.ORDER_LOG_TYPE_NEW_TRACK);
            orderLog.setTypeName("跟单系统-" + trackLog.getTypeName());
            orderLog.setCreateTime(trackLog.getCreateTime());
            StringBuilder sb = new StringBuilder();
            sb.append(trackLog.getContent()).append("（跟单ID：").append(trackLog.getTrackWorkId()).append("）");
            orderLog.setContent(sb.toString());
            orderLog.setBeforeStatusName(trackLog.getBeforeStatusName());
            orderLog.setAfterStatusName(trackLog.getAfterStatusName());
            orderLog.setOperatorType(trackLog.getOperatorType());
            orderLog.setOperator(trackLog.getOperator());
            orderLog.setOperatorTypeName(trackLog.getOperatorTypeName());
            orderLogs.add(orderLog);
        });

        return orderLogs;

    }

    @Override
    public List<OrderLog> findCancelApplyLogsByWorkId(Long workId) {
        if (NumberUtil.isNullOrZero(workId)) {
            return Lists.newArrayList();
        }
        ResponseDTO<List<OrderCancelApplyLogDRO>> listResponseDTO = null;
        try {
            listResponseDTO = orderCancelApplyListRemoteService.listCancelApplyLogByWorkId(workId);
        } catch (Exception e) {
            e.printStackTrace();
            return Collections.EMPTY_LIST;
        }
        List<OrderLog> orderLogs = new ArrayList<>();

        if (!listResponseDTO.isSuccess()) {
            return orderLogs;
        }

        listResponseDTO.getData().forEach(trackLog -> {
            OrderLog orderLog = new OrderLog();
            orderLog.setType(OrderLogConsts.ORDER_LOG_TYPE_CANCEL_APPLY);
            orderLog.setTypeName("跟单系统-" + trackLog.getTypeName());
            orderLog.setCreateTime(trackLog.getCreateTime());
            StringBuilder sb = new StringBuilder();
            sb.append(trackLog.getContent()).append("（取消申请ID：").append(trackLog.getApplyId()).append("）");
            orderLog.setContent(sb.toString());
//            orderLog.setBeforeStatusName(trackLog.getBeforeStatusName());
//            orderLog.setAfterStatusName(trackLog.getAfterStatusName());
            orderLog.setOperatorType(trackLog.getOperatorType());
            orderLog.setOperator(trackLog.getOperator());
            orderLog.setOperatorTypeName(trackLog.getOperatorTypeName());
            orderLogs.add(orderLog);
        });

        return orderLogs;
    }

    @Override
    public OrderLog generateOrderLog(Long orderId, Long workId, int type, String operator,
                                     Long operatorId, Integer operatorType, String content, Date operateTime) {
        // orderWork在此必定不为 null
        OrderWork dbOrderWork = orderWorkService.findOrderWorkByKeySrcMaster(orderId, workId);
        OrderLog orderLog = new OrderLog();
        orderLog.setOrderId(dbOrderWork.getOrderId());
        orderLog.setWorkId(dbOrderWork.getWorkId());
        orderLog.setType(type);
        orderLog.setTypeName(OrderLogConsts.getOrderLogTypeName(type));
        orderLog.setBeforeStatus(dbOrderWork.getStatus());
        orderLog.setBeforeStatusName(OrderStatusConsts.getWorkStatusName(dbOrderWork.getStatus()));
        orderLog.setBeforeResultStatus(dbOrderWork.getResultStatus());
        orderLog.setBeforeResultStatusName(OrderStatusConsts.getWorkResultStatusName(dbOrderWork.getResultStatus()));
        orderLog.setAfterStatus(dbOrderWork.getStatus());
        orderLog.setAfterStatusName(OrderStatusConsts.getWorkStatusName(dbOrderWork.getStatus()));
        orderLog.setAfterResultStatus(dbOrderWork.getResultStatus());
        orderLog.setAfterResultStatusName(OrderStatusConsts.getWorkResultStatusName(
                dbOrderWork.getResultStatus()));
        orderLog.setOperator(operator);
        orderLog.setOperatorId(operatorId);
        orderLog.setOperatorType(operatorType);
        orderLog.setContent(content);
        orderLog.setCreateTime(Optional.ofNullable(operateTime).orElse(DateUtil.getNow()));
        return orderLog;

    }


}
